package com.ssl;


import lombok.extern.slf4j.Slf4j;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

@Slf4j
public final class SecureChatSslContextFactory {

    private static final String PROTOCOL = "TLS";

    private static SSLContext SERVER_CONTEXT;//服务器安全套接字协议

    private static SSLContext CLIENT_CONTEXT;//客户端安全套接字协议

    public static SSLContext getServerContext(String pkPath) throws FileNotFoundException {
        InputStream in =null;
        try {
            in = new FileInputStream(pkPath);
            return getServerContext(in);
        } catch (FileNotFoundException e) {
            log.error("server .jks file not found [{}]", pkPath, e);
            throw e;
        } finally {
            if(in !=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static SSLContext getServerContext(InputStream jksIs){
        if(SERVER_CONTEXT!=null) return SERVER_CONTEXT;

        try{
            //密钥库KeyStore，jks文件就是密钥管理库文件
            // KeyStore.getDefaultType()
            KeyStore ks = KeyStore.getInstance("JKS");
            //加载服务端证书

            //加载服务端的KeyStore  ；sNetty是生成仓库时设置的密码，用于检查密钥库完整性的密码
            ks.load(jksIs, "sNetty".toCharArray());

            //密钥管理器
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            //初始化密钥管理器
            kmf.init(ks, "sNetty".toCharArray());

            //获取安全套接字协议（TLS协议）的对象
            SERVER_CONTEXT= SSLContext.getInstance(PROTOCOL);
            //初始化此上下文
            //参数一：认证的密钥
            // 参数二：对等信任认证
            // 参数三：伪随机数生成器 。 由于单向认证，服务端不用验证客户端，所以第二个参数为null
            SERVER_CONTEXT.init(kmf.getKeyManagers(), null, null);

        }catch(Exception e){
            throw new Error("Failed to initialize the server-side SSLContext", e);
        }finally{
            if(jksIs !=null){
                try {
                    jksIs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        return SERVER_CONTEXT;
    }

    public static SSLContext getClientContext(String pkPath) throws FileNotFoundException {
        InputStream in = null;
        try {
            in = new FileInputStream(pkPath);
            return getClientContext(in);
        } catch (FileNotFoundException e) {
            log.error("client .jks file not found [{}]", pkPath, e);
            throw e;
        } finally {
            if(in !=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static SSLContext getClientContext(InputStream jksIs){
        if(CLIENT_CONTEXT!=null) return CLIENT_CONTEXT;

        try{
            //密钥库KeyStore
            KeyStore tks = KeyStore.getInstance("JKS");
            //加载客户端证书
            tks.load(jksIs, "sNetty".toCharArray());
            //信任库
            TrustManagerFactory tf = TrustManagerFactory.getInstance("SunX509");
            // 初始化信任库
            tf.init(tks);

            CLIENT_CONTEXT = SSLContext.getInstance(PROTOCOL);
            //设置信任证书
            CLIENT_CONTEXT.init(null,tf == null ? null : tf.getTrustManagers(), null);

        }catch(Exception e){
            e.printStackTrace();
            throw new Error("Failed to initialize the client-side SSLContext");
        }finally{
            if(jksIs !=null){
                try {
                    jksIs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return CLIENT_CONTEXT;
    }

}